﻿
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using CCSFeederCameraUI2.Data;
using CCSFeederCameraUI2.Models;
using HalconDotNet;
using Microsoft.Extensions.Logging;
using MvCamCtrl.NET.CameraParams;
using MvCamCtrl.NET;
using NLog;
using Prism.Commands;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System;
using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ViewROI;
using CCSFeederCameraUI2.Services;
using Prism.Events;
using CCSFeederCameraUI2.Data.Extensions;
using System.IO;
using System.Threading;
using CCSFeederCameraUI2.Data.MClass;
using System.Net;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Configuration;
using System.Windows;
using System.Windows.Media.Media3D;

namespace CCSFeederCameraUI2.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        #region 变量
        private static Logger logger = LogManager.GetCurrentClassLogger();
        private ConcurrentQueue<string>[] No1BarcodeList = new ConcurrentQueue<string>[4];
        private ConcurrentQueue<string>[] MachineShiftBarcodes = new ConcurrentQueue<string>[4];
        private bool isCameraCalcDialogShow = false, isPartNumDialogShow = false, isParameterDialogShow = false;
        private readonly IDialogService _dialogService;
        private readonly ICameraService leftCamera;
        private readonly ICameraService rightCamera;
        private readonly IPLCService pLC;
        private readonly IScanner scanner;
        private readonly IEventAggregator aggregator;
        HObject LeftRec1, LeftRec2;
        HObject RightRec1, RightRec2;
        private int MaxGrayDark1, MinGrayLight1; double BrightAreaMin1, DarkAreaMin1;
        private int MaxGrayDark2, MinGrayLight2; double BrightAreaMin2, DarkAreaMin2;
        string ImagePath;int BarLimit;bool IsUseMES;bool IsRepeatBarcode;string RepeatBarcode = string.Empty;
        CancellationTokenSource source1;
        bool[] mesResutl = { false, false, false, false };
        bool finishMES = false,resultMES = false;
        bool hasScaned = false, hasGrabed = false;
        #endregion
        #region 属性
        public string Title { get; set; } = "CCS上料机铝巴检测软件";
        public string Version { get; set; } = "2.1.0";
        private string partNum;
        public string PartNum
        {
            get { return partNum; }
            set { SetProperty(ref partNum, value); }
        }
        private string messageStr = string.Empty;
        public string MessageStr
        {
            get { return messageStr; }
            set { SetProperty(ref messageStr, value); }
        }
        #region halcon
        #region 1#
        private HImage cameraImage1;
        public HImage CameraImage1
        {
            get { return cameraImage1; }
            set { SetProperty(ref cameraImage1, value); }
        }
        private bool cameraRepaint1;
        public bool CameraRepaint1
        {
            get { return cameraRepaint1; }
            set { SetProperty(ref cameraRepaint1, value); }
        }
        private ObservableCollection<ROI> cameraROIList1 = new ObservableCollection<ROI>();
        public ObservableCollection<ROI> CameraROIList1
        {
            get { return cameraROIList1; }
            set { SetProperty(ref cameraROIList1, value); }
        }
        private HObject cameraAppendHObject1;
        public HObject CameraAppendHObject1
        {
            get { return cameraAppendHObject1; }
            set { SetProperty(ref cameraAppendHObject1, value); }
        }
        private HMsgEntry cameraAppendHMessage1;
        public HMsgEntry CameraAppendHMessage1
        {
            get { return cameraAppendHMessage1; }
            set { SetProperty(ref cameraAppendHMessage1, value); }
        }
        private Tuple<string, object> cameraGCStyle1;
        public Tuple<string, object> CameraGCStyle1
        {
            get { return cameraGCStyle1; }
            set { SetProperty(ref cameraGCStyle1, value); }
        }
        #endregion
        #region 2#
        private HImage cameraImage2;
        public HImage CameraImage2
        {
            get { return cameraImage2; }
            set { SetProperty(ref cameraImage2, value); }
        }
        private bool cameraRepaint2;
        public bool CameraRepaint2
        {
            get { return cameraRepaint2; }
            set { SetProperty(ref cameraRepaint2, value); }
        }
        private ObservableCollection<ROI> cameraROIList2 = new ObservableCollection<ROI>();
        public ObservableCollection<ROI> CameraROIList2
        {
            get { return cameraROIList2; }
            set { SetProperty(ref cameraROIList2, value); }
        }
        private HObject cameraAppendHObject2;
        public HObject CameraAppendHObject2
        {
            get { return cameraAppendHObject2; }
            set { SetProperty(ref cameraAppendHObject2, value); }
        }
        private HMsgEntry cameraAppendHMessage2;
        public HMsgEntry CameraAppendHMessage2
        {
            get { return cameraAppendHMessage2; }
            set { SetProperty(ref cameraAppendHMessage2, value); }
        }
        private Tuple<string, object> cameraGCStyle2;
        public Tuple<string, object> CameraGCStyle2
        {
            get { return cameraGCStyle2; }
            set { SetProperty(ref cameraGCStyle2, value); }
        }
        #endregion
        #endregion
        private bool pLCState;
        public bool PLCState
        {
            get { return pLCState; }
            set { SetProperty(ref pLCState, value); }
        }
        private bool lCameraState;
        public bool LCameraState
        {
            get { return lCameraState; }
            set { SetProperty(ref lCameraState, value); }
        }
        private bool rCameraState;
        public bool RCameraState
        {
            get { return rCameraState; }
            set { SetProperty(ref rCameraState, value); }
        }
        private bool scannerState;
        public bool ScannerState
        {
            get { return scannerState; }
            set { SetProperty(ref scannerState, value); }
        }
        private ObservableCollection<ObservableCollection<MachineDisp>> machineLists;
        public ObservableCollection<ObservableCollection<MachineDisp>> MachineLists
        {
            get { return machineLists; }
            set { SetProperty(ref machineLists, value); }
        }
        private ObservableCollection<bool> productUse;
        public ObservableCollection<bool> ProductUse
        {
            get { return productUse; }
            set { SetProperty(ref productUse, value); }
        }
        private int tabSelectedIndex;
        public int TabSelectedIndex
        {
            get { return tabSelectedIndex; }
            set { SetProperty(ref tabSelectedIndex, value); }
        }
        #endregion
        #region 命令
        private DelegateCommand appClosedEventCommand;
        public DelegateCommand AppClosedEventCommand =>
            appClosedEventCommand ?? (appClosedEventCommand = new DelegateCommand(ExecuteAppClosedEventCommand));
        private DelegateCommand appLoadedEventCommand;
        public DelegateCommand AppLoadedEventCommand =>
            appLoadedEventCommand ?? (appLoadedEventCommand = new DelegateCommand(ExecuteAppLoadedEventCommand));
        private DelegateCommand<object> menuCommand;
        public DelegateCommand<object> MenuCommand =>
            menuCommand ?? (menuCommand = new DelegateCommand<object>(ExecuteMenuCommand));
        private DelegateCommand<object> productUseCommand;
        public DelegateCommand<object> ProductUseCommand =>
            productUseCommand ?? (productUseCommand = new DelegateCommand<object>(ExecuteProductUseCommand));

        void ExecuteProductUseCommand(object obj)
        {
            int _index = int.Parse(obj.ToString());
            
            if (!ProductUse[_index])
            {
                //clearBarcode(_index);
            }
            using var mdb = new MDbContext();
            var _param = mdb.MParams.FirstOrDefault(p => p.Name == "ProductUse" && p.Hand == _index && p.PartNum == PartNum);
            if (_param != null)
            {
                _param.Value = ProductUse[_index].ToString();
                mdb.SaveChanges();
            }
        }
        void ExecuteAppClosedEventCommand()
        {
            leftCamera.CloseCamera();
            rightCamera.CloseCamera();
            if (source1 != null)
            {
                source1.Cancel();
            }
            logger.Info("软件关闭");
        }
        void ExecuteMenuCommand(object obj)
        {
            switch (obj.ToString())
            {
                case "左算法":
                    {
                        if (!isCameraCalcDialogShow)
                        {
                            isCameraCalcDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("HandIndex", 0);
                            param.Add("PartNum", PartNum);
                            _dialogService.Show("CameraVisionDialog", param, arg =>
                            {
                                isCameraCalcDialogShow = false;
                            });
                        }
                    }
                    break;
                case "右算法":
                    {
                        if (!isCameraCalcDialogShow)
                        {
                            isCameraCalcDialogShow = true;
                            DialogParameters param = new DialogParameters();
                            param.Add("HandIndex", 1);
                            param.Add("PartNum", PartNum);
                            _dialogService.Show("CameraVisionDialog", param, arg =>
                            {
                                isCameraCalcDialogShow = false;
                            });
                        }
                    }
                    break;
                case "料号":
                    if (!isPartNumDialogShow)
                    {
                        isPartNumDialogShow = true;
                        _dialogService.Show("PartNumDialog", arg =>
                        {
                            isPartNumDialogShow = false;
                        });
                    }
                    break;
                case "参数":
                    if (!isParameterDialogShow)
                    {
                        isParameterDialogShow = true;
                        DialogParameters param = new DialogParameters();
                        param.Add("PartNum", PartNum);
                        _dialogService.Show("ParameterDialog", param, arg =>
                        {
                            isParameterDialogShow = false;
                        });
                    }
                    break;
                
                default:
                    break;
            }
        }
        void ExecuteAppLoadedEventCommand()
        {            
            Task.Run(() => {
                try
                {
                    using var mdb = new MDbContext();
                    var param = mdb.MParams.FirstOrDefault(p => p.Name == "PartNum");
                    if (param != null)
                    {
                        PartNum = param.Value;
                        addMessage($"加载料号:{PartNum}");
                        aggregator.SendMessage($"PartNum;{PartNum}","MES");
                    }
                    LoadFromDb();
                    LoadCameraParam();

                    param = mdb.MParams.FirstOrDefault(p => p.Name == "LeftCameraIP");
                    if (param != null)
                    {
                        LCameraState = leftCamera.OpenCamera(param.Value);
                    }
                    param = mdb.MParams.FirstOrDefault(p => p.Name == "RightCameraIP");
                    if (param != null)
                    {
                        RCameraState = rightCamera.OpenCamera(param.Value);
                    }
                    param = mdb.MParams.FirstOrDefault(p => p.Name == "ScanCOM");
                    if (param != null)
                    {
                        ScannerState = scanner.OpenPort(param.Value);
                    }
                    param = mdb.MParams.FirstOrDefault(p => p.Name == "PLCIp");
                    if (param != null)
                    {
                        PLCState = pLC.Connect(param.Value);
                    }
                    if (LCameraState && RCameraState && ScannerState && PLCState)
                    {
                        source1 = new CancellationTokenSource();
                        CancellationToken token = source1.Token;
                        Task.Run(() => PLCRun(token), token);
                        addMessage("软件开启");
                    }
                    param = mdb.MParams.FirstOrDefault(p => p.Name == "ListenerIp");
                    if (param != null)
                    {
                        Task.Run(() => {
                            try
                            {
                                StartWebServer(param.Value);
                            }
                            catch (Exception ex)
                            {
                                addMessage(ex.Message);
                            }
                        }
                        );
                        Task.Run(() => { Run(param.Value); });
                    }
                }
                catch (Exception ex)
                {
                    addMessage(ex.Message);
                }
            });
        }
        #endregion
        #region 构造函数
        void ImageCallbackFunc1(IntPtr pData, ref MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            if (leftCamera.m_bIsDeviceOpen && pFrameInfo.enPixelType == MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
            {
                try
                {
                    HObject Hobj;
                    int imageSize = (int)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3);
                    byte[] imageData = new byte[imageSize];
                    Marshal.Copy(pData, imageData, 0, imageSize);
                    GCHandle pinnedArray = GCHandle.Alloc(imageData, GCHandleType.Pinned);
                    IntPtr ptr = pinnedArray.AddrOfPinnedObject();
                    HOperatorSet.GenImageInterleaved(out Hobj, ptr, "rgb", pFrameInfo.nWidth, pFrameInfo.nHeight, -1, "byte", 0, 0, 0, 0, -1, 0);
                    leftCamera.ImageQueue.Enqueue(Hobj.CopyObj(1, -1));
                    pinnedArray.Free();
                }
                catch (System.Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
            leftCamera.StopGrabe();
        }
        void ImageCallbackFunc2(IntPtr pData, ref MV_FRAME_OUT_INFO_EX pFrameInfo, IntPtr pUser)
        {
            if (rightCamera.m_bIsDeviceOpen && pFrameInfo.enPixelType == MvGvspPixelType.PixelType_Gvsp_RGB8_Packed)
            {
                try
                {
                    HObject Hobj;
                    int imageSize = (int)(pFrameInfo.nWidth * pFrameInfo.nHeight * 3);
                    byte[] imageData = new byte[imageSize];
                    Marshal.Copy(pData, imageData, 0, imageSize);
                    GCHandle pinnedArray = GCHandle.Alloc(imageData, GCHandleType.Pinned);
                    IntPtr ptr = pinnedArray.AddrOfPinnedObject();
                    HOperatorSet.GenImageInterleaved(out Hobj, ptr, "rgb", pFrameInfo.nWidth, pFrameInfo.nHeight, -1, "byte", 0, 0, 0, 0, -1, 0);
                    rightCamera.ImageQueue.Enqueue(Hobj.CopyObj(1, -1));
                    pinnedArray.Free();
                }
                catch (System.Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
            rightCamera.StopGrabe();
        }
        void Xenon1900_RxDataInd(byte[] data, uint length)
        {
            string result = System.Text.Encoding.UTF8.GetString(data);
            string[] strs = result.Split(new char[] { '\r' });
            if (strs.Length >= 1)
            {
                var bar = result;
                addMessage($"扫到条码：{bar}");
                if (IsRepeatBarcode)
                {
                    return;
                }
                hasScaned = true;
                if (bar.Length > 0)
                {
                    for (int i = 0; i < 4; i++)
                    {
                        if (ProductUse[i])
                        {
                            if (No1BarcodeList[i].Count < BarLimit)
                            {
                                if (!No1BarcodeList[i].Contains(bar))
                                {
                                    TabSelectedIndex = i;                                   
                                    addNewBarcode(bar, i);
                                    if (No1BarcodeList[i].Count == BarLimit)
                                    {
                                        if (IsUseMES)
                                        {
                                            finishMES = false;
                                            aggregator.SendMessage($"CheckBarcode;{string.Join(",", No1BarcodeList[i])};{i}","MES");
                                            int _count = 0;
                                            mesResutl[i] = false;
                                            while (_count < 500)
                                            {
                                                if (finishMES)
                                                {
                                                    mesResutl[i] = resultMES;
                                                    break;
                                                }
                                                System.Threading.Thread.Sleep(20);
                                                _count++;
                                            }
                                            if (!mesResutl[i])
                                            {
                                                clearBarcode(i);
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    addMessage("条码重复");
                                }
                                break;
                            }
                            else
                            {
                                addMessage($"{i + 1}号产品条码已完成");
                            }
                        }
                    }
                }
            }
        }
        public MainWindowViewModel(IContainerProvider containerProvider)
        {
            NlogConfig();
            ProductUse = new ObservableCollection<bool> { true, true, true, true };
            MachineLists = new ObservableCollection<ObservableCollection<MachineDisp>>();
            for (int i = 0; i < 4; i++)
            {
                No1BarcodeList[i] = new ConcurrentQueue<string>();
                MachineShiftBarcodes[i] = new ConcurrentQueue<string>();

                var _MachineList = new ObservableCollection<MachineDisp>();
                var name1 = ConfigurationManager.ConnectionStrings["Name1"].ConnectionString;
                var name2 = ConfigurationManager.ConnectionStrings["Name2"].ConnectionString;
                var name3 = ConfigurationManager.ConnectionStrings["Name3"].ConnectionString;
                var name4 = ConfigurationManager.ConnectionStrings["Name4"].ConnectionString;
                var name5 = ConfigurationManager.ConnectionStrings["Name5"].ConnectionString;
                var name6 = ConfigurationManager.ConnectionStrings["Name6"].ConnectionString;
                _MachineList.Add(new MachineDisp
                {
                    ItemNo = 1,
                    MachineName = name1
                });
                _MachineList.Add(new MachineDisp
                {
                    ItemNo = 2,
                    MachineName = name2
                });
                _MachineList.Add(new MachineDisp
                {
                    ItemNo = 3,
                    MachineName = name3
                });
                _MachineList.Add(new MachineDisp
                {
                    ItemNo = 4,
                    MachineName = name4
                });
                _MachineList.Add(new MachineDisp
                {
                    ItemNo = 5,
                    MachineName = name5
                });
                _MachineList.Add(new MachineDisp
                {
                    ItemNo = 6,
                    MachineName = name6
                });
                MachineLists.Add(_MachineList);
            }
            HOperatorSet.ResetObjDb(5000, 5000, 1);
            HOperatorSet.SetSystem("clip_region", "false");
            HOperatorSet.SetSystem("store_empty_region", "true");

            _dialogService = containerProvider.Resolve<IDialogService>();

            leftCamera = containerProvider.Resolve<ICameraService>("LeftCamera");
            leftCamera.ImageQueue = new ConcurrentQueue<HObject>();
            leftCamera.ImageCallbackFunc = ImageCallbackFunc1;
            rightCamera = containerProvider.Resolve<ICameraService>("RightCamera");
            rightCamera.ImageQueue = new ConcurrentQueue<HObject>();
            rightCamera.ImageCallbackFunc = ImageCallbackFunc2;
            pLC = containerProvider.Resolve<IPLCService>("PLC");
            scanner = containerProvider.Resolve<IScanner>("Scanner");
            scanner.RxDataInd = Xenon1900_RxDataInd;
            aggregator = containerProvider.Resolve<IEventAggregator>();
            aggregator.ResgiterMessage(arg =>
            {
                string[] strs = arg.Message.Split(new char[] { ';' });
                switch (strs[0])
                {
                    case "PartNumChanged":
                        {
                            PartNum = strs[1];              

                            addMessage($"更换料号:{PartNum}");
                        }
                        break;
                    case "ReloadParam":
                        {
                            LoadCameraParam();
                            LoadFromDb();
                            addMessage("加载参数");
                        }
                        break;
                    default:
                        break;
                }
            }, "Run");
            aggregator.ResgiterMessage(arg => {
                string[] strs = arg.Message.Split(new char[] { ';' });
                switch (strs[0])
                {
                    case "MESResult":
                        finishMES = true;
                        resultMES = bool.Parse(strs[1]);
                        break;
                    default:
                        break;
                }
            }, "MES");
        }
        #endregion
        #region 功能函数
        private void NlogConfig()
        {
            var config = new NLog.Config.LoggingConfiguration();

            // Targets where to log to: File and Console
            var logfile = new NLog.Targets.FileTarget("logfile") { FileName = "${basedir}/logs/${shortdate}.log", Layout = "${longdate}|${level:uppercase=true}|${message}" };
            var logconsole = new NLog.Targets.ConsoleTarget("logconsole");

            // Rules for mapping loggers to targets            
            config.AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, logconsole);
            config.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, logfile);

            // Apply config           
            NLog.LogManager.Configuration = config;
        }
        private void addMessage(string str)
        {
            logger.Info(str);
            string[] s = MessageStr.Split('\n');
            if (s.Length > 1000)
            {
                MessageStr = "";
            }
            if (MessageStr != "")
            {
                MessageStr += "\n";
            }
            MessageStr += DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " " + str;
        }
        void LoadFromDb()
        {
            using var mdb = new MDbContext();
            var _param = mdb.MParams.FirstOrDefault(p => p.Name == "MaxGrayDark" && p.Hand == 0 && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = int.TryParse(_param.Value, out var v1);
                if (r)
                {
                    MaxGrayDark1 = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "MinGrayLight" && p.Hand == 0 && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = int.TryParse(_param.Value, out var v1);
                if (r)
                {
                    MinGrayLight1 = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "BrightAreaMin" && p.Hand == 0 && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = double.TryParse(_param.Value, out var v1);
                if (r)
                {
                    BrightAreaMin1 = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "DarkAreaMin" && p.Hand == 0 && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = double.TryParse(_param.Value, out var v1);
                if (r)
                {
                    DarkAreaMin1 = v1;
                }
            }

            _param = mdb.MParams.FirstOrDefault(p => p.Name == "MaxGrayDark" && p.Hand == 1 && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = int.TryParse(_param.Value, out var v1);
                if (r)
                {
                    MaxGrayDark2 = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "MinGrayLight" && p.Hand == 1 && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = int.TryParse(_param.Value, out var v1);
                if (r)
                {
                    MinGrayLight2 = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "BrightAreaMin" && p.Hand == 1 && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = double.TryParse(_param.Value, out var v1);
                if (r)
                {
                    BrightAreaMin2 = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "DarkAreaMin" && p.Hand == 1 && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = double.TryParse(_param.Value, out var v1);
                if (r)
                {
                    DarkAreaMin2 = v1;
                }
            }

            //ImagePath
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "ImagePath");
            if (_param != null)
            {
                ImagePath = _param.Value;
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "BarLimit" && p.PartNum == PartNum);
            if (_param != null)
            {
                var r = int.TryParse(_param.Value, out var v1);
                if (r)
                {
                    BarLimit = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "IsUseMES");
            if (_param != null)
            {
                var r = bool.TryParse(_param.Value, out var v1);
                if (r)
                {
                    IsUseMES = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "IsRepeatBarcode");
            if (_param != null)
            {
                var r = bool.TryParse(_param.Value, out var v1);
                if (r)
                {
                    IsRepeatBarcode = v1;
                }
            }
            _param = mdb.MParams.FirstOrDefault(p => p.Name == "RepeatBarcode");
            if (_param != null)
            {
                RepeatBarcode = _param.Value;
            }
            for (int i = 0; i < 4; i++)
            {
                _param = mdb.MParams.FirstOrDefault(p => p.Name == "ProductUse" && p.Hand == i && p.PartNum == PartNum);
                if (_param != null)
                {
                    var r = bool.TryParse(_param.Value, out var v1);
                    if (r)
                    {
                        ProductUse[i] = v1;
                        if (v1)
                        {
                            TabSelectedIndex = i;
                        }
                    }
                }
                else
                {
                    ProductUse[i] = true;
                    mdb.MParams.Add(new MParam
                    {
                        Name = "ProductUse",
                        Value = ProductUse[i].ToString(),
                        Hand = i,
                        PartNum = PartNum
                    });
                    mdb.SaveChanges();
                }
            }

            for (int j = 0; j < 4; j++)
            {
                if (ProductUse[j])
                {
                    if (IsRepeatBarcode)
                    {
                        string _bar = string.Empty;
                        for (int k = 0; k < BarLimit; k++)
                        {
                            _bar += RepeatBarcode;
                            if (k < BarLimit - 1)
                            {
                                _bar += ";";
                            }
                        }
                        for (int i = 1; i < 7; i++)
                        {
                            var _barcode = mdb.MBarcodes.FirstOrDefault(b => b.ItemNo == i && b.ProductIndex == j);
                            if (_barcode != null)
                            {
                                _barcode.Barcode = _bar;
                            }
                            else
                            {
                                mdb.MBarcodes.Add(new MBarcode
                                {
                                    ItemNo = i,
                                    ProductIndex = j,
                                    Barcode = _bar
                                });
                            }
                            mdb.SaveChanges();
                        }
                    }
                   
                    //后面工站
                    for (int i = 6; i > 1; i--)
                    {
                        var _barcode = mdb.MBarcodes.FirstOrDefault(b => b.ItemNo == i && b.ProductIndex == j);
                        if (_barcode != null)
                        {
                            addToMachineShiftQueue(_barcode.Barcode == null ? string.Empty : _barcode.Barcode, j);
                        }
                        else
                        {
                            mdb.MBarcodes.Add(new MBarcode
                            {
                                ItemNo = i,
                                ProductIndex = j,
                                Barcode = string.Empty
                            });
                            mdb.SaveChanges();
                            addToMachineShiftQueue(string.Empty, j);
                        }
                    }
                    var mbarcodeArr = MachineShiftBarcodes[j].ToArray().Reverse().ToArray();
                    for (int i = 0; i < mbarcodeArr.Length; i++)
                    {
                        var disp = MachineLists[j].FirstOrDefault(m => m.ItemNo == i + 2);
                        if (disp != null)
                        {
                            if (mbarcodeArr[i] != string.Empty)
                            {
                                string[] bars = mbarcodeArr[i].Split(new char[] { ';' });
                                disp.BarcodeList = bars.ToList();
                            }
                            else
                            {
                                disp.BarcodeList = null;
                            }
                        }
                    }
                    //上料工站
                    {
                        while (No1BarcodeList[j].Count > 0)
                        {
                            No1BarcodeList[j].TryDequeue(out _);
                        }
                        var _barcode = mdb.MBarcodes.FirstOrDefault(b => b.ItemNo == 1 && b.ProductIndex == j);
                        if (_barcode != null)
                        {
                            if (_barcode.Barcode != null)
                            {
                                string[] bars = _barcode.Barcode.Split(new char[] { ';' });
                                for (int k = 0; k < bars.Length; k++)
                                {
                                    if (bars[k] != string.Empty)
                                    {
                                        No1BarcodeList[j].Enqueue(bars[k]);
                                    }
                                }
                            }
                        }
                        else
                        {
                            mdb.MBarcodes.Add(new MBarcode
                            {
                                ItemNo = 1,
                                ProductIndex = j,
                                Barcode = string.Empty
                            });
                            mdb.SaveChanges();
                        }
                        var disp = MachineLists[j].FirstOrDefault(m => m.ItemNo == 1);
                        if (disp != null)
                        {
                            disp.BarcodeList = No1BarcodeList[j].ToList();
                        }
                    }

                }
            }

        }
        void LoadCameraParam()
        {
            try
            {
                string dirPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, PartNum, "Camera\\0");
                Directory.CreateDirectory(dirPath);
                HOperatorSet.ReadRegion(out LeftRec1, System.IO.Path.Combine(dirPath, "Rec1.hobj"));
                HOperatorSet.ReadRegion(out LeftRec2, System.IO.Path.Combine(dirPath, "Rec2.hobj"));

                dirPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, PartNum, "Camera\\1");
                Directory.CreateDirectory(dirPath);
                HOperatorSet.ReadRegion(out RightRec1, System.IO.Path.Combine(dirPath, "Rec1.hobj"));
                HOperatorSet.ReadRegion(out RightRec2, System.IO.Path.Combine(dirPath, "Rec2.hobj"));
            }
            catch (Exception ex)
            {
                addMessage(ex.Message);
            }
        }
        private void Run(string listenerIp)
        {
            try
            {
                TcpListener server = null;
                // Set the TcpListener on port 13000.
                int port = 13001;
                IPAddress localAddr = IPAddress.Parse(listenerIp);
                // TcpListener server = new TcpListener(port);
                server = new TcpListener(localAddr, port);

                // Start listening for client requests.
                server.Start();

                // Buffer for reading data
                byte[] bytes = new Byte[256];
                string data = null;

                // Enter the listening loop.
                while (true)
                {

                    Console.WriteLine("Waiting for a connection... ");

                    // Perform a blocking call to accept requests.
                    // You could also use server.AcceptSocket() here.
                    TcpClient client = server.AcceptTcpClient();

                    try
                    {
                        data = null;

                        // Get a stream object for reading and writing
                        NetworkStream stream = client.GetStream();
                        stream.ReadTimeout = 500;

                        int i;

                        // Loop to receive all the data sent by the client.
                        while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            // Translate data bytes to a ASCII string.
                            data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                            try
                            {
                                Console.WriteLine(data);

                                var strs = data.Split(new char[] { ':' });
                                switch (strs[0])
                                {
                                    case "Connect":
                                        {
                                            byte[] msg = System.Text.Encoding.ASCII.GetBytes("Ok");
                                            // Send back a response.
                                            stream.Write(msg, 0, msg.Length);
                                        }
                                        break;
                                    case "GetBarcode":
                                        {
                                            bool r = int.TryParse(strs[1], out var machineIndex);
                                            if (r)
                                            {
                                                if (machineIndex >= 0 && machineIndex < 6)
                                                {
                                                    List<string> resultStrs = new List<string>();
                                                    using var mdb = new MDbContext();
                                                    for (int j = 0; j < 4; j++)
                                                    {
                                                        if (ProductUse[j])
                                                        {
                                                            var _barcode = mdb.MBarcodes.FirstOrDefault(bar => bar.ItemNo == machineIndex + 1 && bar.ProductIndex == j);
                                                            resultStrs.Add(_barcode.Barcode);
                                                        }
                                                        else
                                                        {
                                                            resultStrs.Add(string.Empty);
                                                        }
                                                    }
                                                    byte[] msg = System.Text.Encoding.ASCII.GetBytes(string.Join("|", resultStrs));
                                                    // Send back a response.
                                                    stream.Write(msg, 0, msg.Length);
                                                }
                                                else
                                                {
                                                    byte[] msg = System.Text.Encoding.ASCII.GetBytes("Error");
                                                    // Send back a response.
                                                    stream.Write(msg, 0, msg.Length);
                                                }
                                            }
                                            else
                                            {
                                                byte[] msg = System.Text.Encoding.ASCII.GetBytes("Error");
                                                // Send back a response.
                                                stream.Write(msg, 0, msg.Length);
                                            }
                                        }
                                        break;
                                    default:
                                        {
                                            byte[] msg = System.Text.Encoding.ASCII.GetBytes("Unknow");
                                            // Send back a response.
                                            stream.Write(msg, 0, msg.Length);
                                        }
                                        break;
                                }
                            }
                            catch (Exception ex)
                            {
                                byte[] msg = System.Text.Encoding.ASCII.GetBytes("Error");
                                // Send back a response.
                                stream.Write(msg, 0, msg.Length);
                                logger.Error(ex);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.Error(ex);
                    }
                    // Shutdown and end connection
                    client.Close();
                }
                server.Stop();
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }

        }
        private void PLCRun(CancellationToken token)
        {
            bool lastscanSta = false;
            DateTime barSuccessMoment = DateTime.Now;
            int ccount = 0;
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    return;
                }
                try
                {
                    if (pLC.Connected)
                    {
                        bool scanSta = true;
                        for (int i = 0; i < 4; i++)
                        {
                            if (ProductUse[i] && No1BarcodeList[i].Count < BarLimit)
                            {
                                scanSta = false;
                                break;
                            }
                        }
                        if (ccount > 5) {
                            pLC.WriteMCoil(2583, scanSta || !hasScaned || IsRepeatBarcode);//通知PLC条码状态
                            ccount = 0;
                        }
                        ccount++;
                        if (lastscanSta != scanSta)
                        {
                            if (scanSta)
                            {
                                barSuccessMoment = DateTime.Now;
                            }
                            lastscanSta = scanSta;                            
                        }
                        if (!IsRepeatBarcode)
                        {
                            var x6 = pLC.ReadXCoils(6, 1);
                            if (x6 != null)
                            {
                                var x30 = pLC.ReadXCoils(24, 1);
                                if (x30 != null)
                                {
                                    if (!x6[0] || !x30[0])
                                    {
                                        if (lastscanSta)
                                        {
                                            if ((DateTime.Now - barSuccessMoment).TotalSeconds > 5 && !hasGrabed)
                                            {
                                                addMessage("触碰光栅，条码清空");

                                                System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
                                                {
                                                    for (int i = 0; i < 4; i++)
                                                    {
                                                        clearBarcode(i);
                                                    }
                                                }));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        var mcoils = pLC.ReadMCoils(5000, 8);
                        if (mcoils != null)
                        {
                            if (mcoils[2])
                            {
                                hasGrabed = true;
                                addMessage("左侧触发拍照");
                                CameraImage1 = null;
                                CameraAppendHObject1 = null;
                                CameraAppendHMessage1 = null;
                                pLC.WriteMCoil(5002, false); pLC.WriteMCoil(5104, false); pLC.WriteMCoil(5105, false);

                                if (leftCamera.m_bIsDeviceOpen)
                                {
                                    Task.Run(async () =>
                                    {
                                        var r = await GrabImage(leftCamera, 5000);
                                        if (r)
                                        {
                                            if (leftCamera.ImageQueue.TryDequeue(out var mimage))
                                            {
                                                HOperatorSet.Decompose3(mimage, out var Red, out var Green, out var Blue);
                                                string dirPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, PartNum, "Camera\\0");

                                                bool r1 = false, r2 = false; HObject r_region;
                                                HOperatorSet.GenEmptyRegion(out r_region);
                                                HOperatorSet.CopyObj(LeftRec1, out var rec1, 1, -1);
                                                HOperatorSet.ReduceDomain(Blue, rec1, out var imageReduced);
                                                HOperatorSet.Threshold(imageReduced, out var bright, 0, MinGrayLight1);
                                                HOperatorSet.CountObj(bright, out var number);
                                                double brightp = 0;
                                                if (number > 0)
                                                {
                                                    HOperatorSet.Union2(r_region, bright, out r_region);
                                                    HOperatorSet.RegionFeatures(bright, "area", out var area);
                                                    HOperatorSet.RegionFeatures(rec1, "area", out var rec1area);
                                                    brightp = area.D / rec1area.D;
                                                    if (brightp >= BrightAreaMin1)
                                                    {
                                                        r1 = false;
                                                    }
                                                    else
                                                    {
                                                        r1 = true;
                                                    }
                                                }
                                                else
                                                {
                                                    r1 = true;
                                                }
                                                HOperatorSet.CopyObj(LeftRec2, out var rec2, 1, -1);
                                                HOperatorSet.ReduceDomain(Blue, rec2, out imageReduced);
                                                HOperatorSet.Threshold(imageReduced, out var dark, MaxGrayDark1, 255);
                                                HOperatorSet.CountObj(bright, out number);
                                                double dartp = 0;
                                                if (number > 0)
                                                {
                                                    HOperatorSet.Union2(r_region, dark, out r_region);
                                                    HOperatorSet.RegionFeatures(dark, "area", out var area);
                                                    HOperatorSet.RegionFeatures(rec2, "area", out var rec2area);
                                                    dartp = area.D / rec2area.D;
                                                    if (dartp >= DarkAreaMin1)
                                                    {
                                                        r2 = false;
                                                    }
                                                    else
                                                    {
                                                        r2 = true;
                                                    }
                                                }
                                                else
                                                {
                                                    r2 = true;
                                                }
                                                imageReduced.Dispose();
                                                Red.Dispose();
                                                Green.Dispose();
                                                Blue.Dispose();
                                                rec1.Dispose();
                                                rec2.Dispose();
                                                bright.Dispose();
                                                dark.Dispose();

                                                if (!r1 || !r2)
                                                {
                                                    pLC.WriteMCoil(5105, true);
                                                    addMessage("左检测结果:NG");
                                                }
                                                else
                                                {
                                                    pLC.WriteMCoil(5104, true);
                                                    addMessage("左检测结果:OK");
                                                }

                                                System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
                                                {
                                                    CameraImage1 = new HImage(mimage);
                                                    CameraGCStyle1 = new Tuple<string, object>("Color", "red");
                                                    CameraGCStyle1 = new Tuple<string, object>("DrawMode", "fill");
                                                    CameraAppendHObject1 = r_region;
                                                    CameraAppendHMessage1 = new HMsgEntry($"亮色:{brightp:p1}\n暗色:{dartp:p1}", 10, 300, _coordSystem: "window", _genParamName: new HTuple().TupleConcat("box_color"), _genParamValue: new HTuple().TupleConcat("firebrick"),
                                                                            _color: "white", _Size: 18);
                                              
                                                    if (!r1 || !r2)
                                                    {
                                                        CameraAppendHMessage1 = new HMsgEntry("NG", 10, 10, _coordSystem: "window", _genParamName: new HTuple().TupleConcat("box_color"), _genParamValue: new HTuple().TupleConcat("red"),
                                                                            _color: "white", _Size: 22);
                                                        if (!IsRepeatBarcode)
                                                        {
                                                            for (int i = 0; i < 4; i++)
                                                            {
                                                                clearBarcode(i);
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        CameraAppendHMessage1 = new HMsgEntry("OK", 10, 10, _coordSystem: "window", _genParamName: new HTuple().TupleConcat("box_color"), _genParamValue: new HTuple().TupleConcat("green"),
                                                                            _color: "white", _Size: 22);
                                                    }
                                                }));
                                                Task.Run(() =>
                                                {
                                                    try
                                                    {
                                                        string dirpath = System.IO.Path.Combine(ImagePath, PartNum, "Image_L");
                                                        Directory.CreateDirectory(dirpath);
                                                        HOperatorSet.WriteImage(mimage, "jpeg", 0, System.IO.Path.Combine(dirpath, $"{DateTime.Now:yyyyMMddHHmmss}_L.jpg"));
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        addMessage(ex.Message);
                                                    }
                                                });
                                            }
                                            else
                                            {
                                                pLC.WriteMCoil(5105, true);
                                                addMessage("左拍照失败");
                                            }
                                        }
                                        else
                                        {
                                            pLC.WriteMCoil(5105, true);
                                            addMessage("左拍照失败");
                                        }
                                    });
                                }
                                else
                                {
                                    pLC.WriteMCoil(5105, true);
                                    addMessage("左相机未打开");
                                }
                            }
                            if (mcoils[3])
                            {
                                hasGrabed = true;
                                addMessage("右侧触发拍照");
                                CameraImage2 = null;
                                CameraAppendHObject2 = null;
                                CameraAppendHMessage2 = null;
                                pLC.WriteMCoil(5003, false); pLC.WriteMCoil(5106, false); pLC.WriteMCoil(5107, false);

                                if (rightCamera.m_bIsDeviceOpen)
                                {
                                    Task.Run(async () =>
                                    {
                                        var r = await GrabImage(rightCamera, 5000);
                                        if (r)
                                        {
                                            if (rightCamera.ImageQueue.TryDequeue(out var mimage))
                                            {
                                                HOperatorSet.Decompose3(mimage, out var Red, out var Green, out var Blue);
                                                string dirPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, PartNum, "Camera\\1");

                                                bool r1 = false, r2 = false; HObject r_region;
                                                HOperatorSet.GenEmptyRegion(out r_region);
                                                HOperatorSet.CopyObj(RightRec1, out var rec1, 1, -1);
                                                HOperatorSet.ReduceDomain(Blue, rec1, out var imageReduced);
                                                HOperatorSet.Threshold(imageReduced, out var bright, 0, MinGrayLight2);
                                                HOperatorSet.CountObj(bright, out var number);
                                                double brightp = 0;
                                                if (number > 0)
                                                {
                                                    HOperatorSet.Union2(r_region, bright, out r_region);
                                                    HOperatorSet.RegionFeatures(bright, "area", out var area);
                                                    HOperatorSet.RegionFeatures(rec1, "area", out var rec1area);
                                                    brightp = area.D / rec1area.D;
                                                    if (brightp >= BrightAreaMin2)
                                                    {
                                                        r1 = false;
                                                    }
                                                    else
                                                    {
                                                        r1 = true;
                                                    }
                                                }
                                                else
                                                {
                                                    r1 = true;
                                                }
                                                HOperatorSet.CopyObj(RightRec2, out var rec2, 1, -1);
                                                HOperatorSet.ReduceDomain(Blue, rec2, out imageReduced);
                                                HOperatorSet.Threshold(imageReduced, out var dark, MaxGrayDark2, 255);
                                                HOperatorSet.CountObj(bright, out number);
                                                double dartp = 0;
                                                if (number > 0)
                                                {
                                                    HOperatorSet.Union2(r_region, dark, out r_region);
                                                    HOperatorSet.RegionFeatures(dark, "area", out var area);
                                                    HOperatorSet.RegionFeatures(rec2, "area", out var rec2area);
                                                    dartp = area.D / rec2area.D;
                                                    if (dartp >= DarkAreaMin2)
                                                    {
                                                        r2 = false;
                                                    }
                                                    else
                                                    {
                                                        r2 = true;
                                                    }
                                                }
                                                else
                                                {
                                                    r2 = true;
                                                }
                                                imageReduced.Dispose();
                                                Red.Dispose();
                                                Green.Dispose();
                                                Blue.Dispose();
                                                rec1.Dispose();
                                                rec2.Dispose();
                                                bright.Dispose();
                                                dark.Dispose();


                                                if (!r1 || !r2)
                                                {
                                                    pLC.WriteMCoil(5107, true);
                                                    addMessage("右检测结果:NG");
                                                }
                                                else
                                                {
                                                    pLC.WriteMCoil(5106, true);
                                                    addMessage("右检测结果:OK");
                                                }

                                                System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
                                                {
                                                    CameraImage2 = new HImage(mimage);
                                                    CameraGCStyle2 = new Tuple<string, object>("Color", "red");
                                                    CameraGCStyle2 = new Tuple<string, object>("DrawMode", "fill");
                                                    CameraAppendHObject2 = r_region;
                                                    CameraAppendHMessage2 = new HMsgEntry($"亮色:{brightp:p1}\n暗色:{dartp:p1}", 10, 300, _coordSystem: "window", _genParamName: new HTuple().TupleConcat("box_color"), _genParamValue: new HTuple().TupleConcat("firebrick"),
                                                                       _color: "white", _Size: 18);
                                                    if (!r1 || !r2)
                                                    {

                                                        CameraAppendHMessage2 = new HMsgEntry("NG", 10, 10, _coordSystem: "window", _genParamName: new HTuple().TupleConcat("box_color"), _genParamValue: new HTuple().TupleConcat("red"),
                                                                        _color: "white", _Size: 22);
                                                        if (!IsRepeatBarcode)
                                                        {
                                                            for (int i = 0; i < 4; i++)
                                                            {
                                                                clearBarcode(i);
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        CameraAppendHMessage2 = new HMsgEntry("OK", 10, 10, _coordSystem: "window", _genParamName: new HTuple().TupleConcat("box_color"), _genParamValue: new HTuple().TupleConcat("green"),
                                                                        _color: "white", _Size: 22);

                                                    }
                                                }));
                                                Task.Run(() =>
                                                {
                                                    try
                                                    {
                                                        string dirpath = System.IO.Path.Combine(ImagePath, PartNum, "Image_R");
                                                        Directory.CreateDirectory(dirpath);
                                                        HOperatorSet.WriteImage(mimage, "jpeg", 0, System.IO.Path.Combine(dirpath, $"{DateTime.Now:yyyyMMddHHmmss}_R.jpg"));
                                                    }
                                                    catch (Exception ex)
                                                    {
                                                        addMessage(ex.Message);
                                                    }
                                                });
                                            }
                                            else
                                            {
                                                pLC.WriteMCoil(5107, true);
                                                addMessage("右拍照失败");
                                            }
                                        }
                                        else
                                        {
                                            pLC.WriteMCoil(5107, true);
                                            addMessage("右拍照失败");
                                        }
                                    });
                                }
                                else
                                {
                                    pLC.WriteMCoil(5107, true);
                                    addMessage("右相机未打开");
                                }
                            }
                        }
                        var m2540 = pLC.ReadMCoils(2540, 2);
                        if (m2540 != null)
                        {
                            if (m2540[0])
                            {
                                addMessage("收到M2540信号");
                                pLC.WriteMCoil(2540, false);
                                pLC.WriteMCoil(2580, false);

                                bool r1 = true;
                                for (int i = 0; i < 4; i++)
                                {
                                    if (ProductUse[i] && No1BarcodeList[i].Count < BarLimit)
                                    {
                                        r1 = false;
                                        break;
                                    }
                                }

                                if (r1)
                                {
                                    pLC.WriteMCoil(2581, true);
                                    addMessage("上料扫码状态:OK");
                                }
                                else
                                {
                                    pLC.WriteMCoil(2581, false);
                                    addMessage("上料扫码状态:NG");
                                }

                                pLC.WriteMCoil(2580, true);
                                addMessage("置位M2580");

                            }
                            if (m2540[1])
                            {
                                pLC.WriteMCoil(2541, false);
                                pLC.WriteMCoil(2582, false);

                                if (!IsRepeatBarcode)
                                {
                                    System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
                                    {
                                        bool r = true;
                                        for (int i = 0; i < 4; i++)
                                        {
                                            if (ProductUse[i] && !mesResutl[i])
                                            {
                                                r = false;
                                                break;
                                            }
                                        }
                                        if (!r && IsUseMES)
                                        {
                                            addMessage("移料：MES未上传");
                                            for (int j = 0; j < 4; j++)
                                            {
                                                clearBarcode(j);
                                            }
                                        }
                                        for (int j = 0; j < 4; j++)
                                        {
                                            shiftMachineCmd(j);
                                        }
                                        for (int i = 0; i < 4; i++)
                                        {
                                            mesResutl[i] = false;
                                        }
                                    }));
                                }
                                pLC.WriteMCoil(2582, true);
                                addMessage("移料完成");
                                hasScaned = false;
                                hasGrabed = false;
                            }
                        }
                    }

                }
                catch { }

                Thread.Sleep(200);
            }
        }
        async Task<bool> GrabImage(ICameraService _camera, int timeout)
        {
            bool restult = false;
            while (_camera.ImageQueue.Count > 0)
            {
                _camera.ImageQueue.TryDequeue(out var image);
            }
            _camera.StartGrabe();
            Task task = new Task(() =>
            {
                while (_camera.ImageQueue.Count == 0) Thread.Sleep(20);
            });
            var delay = Task.Delay(timeout);
            task.Start();
            if (await Task.WhenAny(task, delay) == delay)
            {
                restult = false;
            }
            else
            {
                restult = true;
            }
            _camera.StopGrabe();
            return restult;
        }
        void addNewBarcode(string str, int productIndex)
        {
            No1BarcodeList[productIndex].Enqueue(str);
            while (No1BarcodeList[productIndex].Count > BarLimit)
            {
                No1BarcodeList[productIndex].TryDequeue(out _);
            }
            var machine = MachineLists[productIndex].FirstOrDefault(m => m.ItemNo == 1);
            if (machine != null)
            {
                machine.BarcodeList = No1BarcodeList[productIndex].ToList();
            }
            using var mdb = new MDbContext();
            var _barcode = mdb.MBarcodes.FirstOrDefault(b => b.ItemNo == 1 && b.ProductIndex == productIndex);
            if (_barcode != null)
            {
                _barcode.Barcode = string.Join(";", No1BarcodeList[productIndex].ToList());
                mdb.SaveChanges();
            }
        }
        void addToMachineShiftQueue(string str, int productIndex)
        {
            MachineShiftBarcodes[productIndex].Enqueue(str);
            if (MachineShiftBarcodes[productIndex].Count > 5)
            {
                MachineShiftBarcodes[productIndex].TryDequeue(out _);
            }
        }
        void shiftMachineCmd(int productIndex)
        {
            if (No1BarcodeList[productIndex].Count > 0)
            {
                addToMachineShiftQueue(string.Join(";", No1BarcodeList[productIndex].ToList()), productIndex);
            }
            else
            {
                addToMachineShiftQueue(string.Empty, productIndex);
            }
            while (No1BarcodeList[productIndex].Count > 0)
            {
                No1BarcodeList[productIndex].TryDequeue(out _);
            }
            {
                var disp = MachineLists[productIndex].FirstOrDefault(m => m.ItemNo == 1);
                if (disp != null)
                {
                    disp.BarcodeList = null;
                }
                using var mdb = new MDbContext();
                var _barcode = mdb.MBarcodes.FirstOrDefault(b => b.ItemNo == 1 && b.ProductIndex == productIndex);
                if (_barcode != null)
                {
                    _barcode.Barcode = string.Empty;
                    mdb.SaveChanges();
                }
            }

            var mbarcodeArr = MachineShiftBarcodes[productIndex].ToArray().Reverse().ToArray();

            for (int i = 0; i < mbarcodeArr.Length; i++)
            {
                var disp = MachineLists[productIndex].FirstOrDefault(m => m.ItemNo == i + 2);
                if (disp != null)
                {
                    if (mbarcodeArr[i] != string.Empty)
                    {
                        string[] bars = mbarcodeArr[i].Split(new char[] { ';' });
                        disp.BarcodeList = bars.ToList();
                    }
                    else
                    {
                        disp.BarcodeList = null;
                    }
                }
                using var mdb = new MDbContext();
                var _barcode = mdb.MBarcodes.FirstOrDefault(b => b.ItemNo == i + 2 && b.ProductIndex == productIndex);
                if (_barcode != null)
                {
                    _barcode.Barcode = mbarcodeArr[i];
                    mdb.SaveChanges();
                }
            }
        }

        void clearBarcode(int productIndex)
        {
            while (No1BarcodeList[productIndex].Count > 0)
            {
                No1BarcodeList[productIndex].TryDequeue(out _);
            }
            var machine = MachineLists[productIndex].FirstOrDefault(m => m.ItemNo == 1);
            if (machine != null)
            {
                machine.BarcodeList = No1BarcodeList[productIndex].ToList();
            }
            using var mdb = new MDbContext();
            var _barcode = mdb.MBarcodes.FirstOrDefault(b => b.ItemNo == 1 && b.ProductIndex == productIndex);
            if (_barcode != null)
            {
                _barcode.Barcode = string.Empty;
                mdb.SaveChanges();
            }
        }
        private void StartWebServer(string ip)
        {
            var builder = WebHost.CreateDefaultBuilder();
            var app = builder
              .UseKestrel(options => options.Listen(IPAddress.Parse(ip), 8080))
              //.UseContentRoot(Directory.GetCurrentDirectory())
              //.UseWebRoot(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"))
              .ConfigureServices((service) => {
                  service.AddControllers();
                  //service.AddDbContext
              }).Configure(app => {
                  app.UseRouting();
                  app.UseAuthorization();
                  app.UseEndpoints(endpoints =>
                  {
                      endpoints.MapControllers();
                  });
              }).Build();
            app.Run();
        }
        #endregion
    }
}
